/**
 * 
 */
package org.dragonfire.dasm.instr;

import java.util.ArrayList;

import org.dragonfire.dasm.Command;
import org.dragonfire.dasm.CompileException;
import org.dragonfire.dasm.DASM;
import org.dragonfire.dasm.Listing;
import org.dragonfire.util.DString;

/**
 * @author Darth Android
 * @date Jul 13, 2007
 */
public class Macro extends CommandDef {

	private String[] code;

	public Macro(String name, String[] params, String[] code) {
		super(name, validateMacroParams(params));
		this.code = code;
	}

	public static String[] validateMacroParams(String[] paramTypes) {
		if (paramTypes == null)
			paramTypes = new String[0];
		for (int i = 0; i < paramTypes.length; i++) {
			paramTypes[i] = validateMacroParam(paramTypes[i]);
		}
		return paramTypes;
	}

	public static String validateMacroParam(String paramType) {
		if (paramType == null)
			throw new IllegalArgumentException("paramType may not be null!");
		if (!paramType.contains(":")) {
			paramType = "V:" + paramType;
		}
		String[] parts = DString.splitTopLevel(paramType, ':');
		parts = DString.trim(parts);
		if (parts.length < 1 || parts[0].length() != 1)
			throw new CompileException("ERROR_PARAM_TYPE_MALFORMED", paramType);
		char type = parts[0].toUpperCase().charAt(0);
		if (parts.length < 2)
			throw new CompileException("ERROR_PARAM_TYPE_TOO_SHORT", type + "", 2);
		try {
			switch (type) {
				case 'V':
					if (!parts[1].matches(DASM.WORD_REGEX))
						throw new CompileException("ERROR_VAR_REQUIRED", parts[1]);
					paramType = "V:" + parts[1];
					break;
				case 'S':
					if (!parts[1].matches(DASM.WORD_REGEX))
						throw new CompileException("ERROR_VAR_REQUIRED", parts[1]);
					paramType = "S:" + parts[1];
					break;
				case 'R':
					if (parts.length < 3)
						throw new CompileException("ERROR_PARAM_TYPE_TOO_SHORT", type + "", 3);
					int classID = new Integer(parts[2]);
					paramType = "R:" + parts[1] + ":" + classID;
					break;
				case 'L':
					String text = parts[1].toLowerCase();
					paramType = "L:" + text;
					break;
				default:
					throw new CompileException("ERROR_INVALID_PARAM_TYPE", type + "");
			}
		} catch (NumberFormatException ne) {
			throw new CompileException("ERROR_INVALID_PARAM_TYPE_SIZE", type + "", parts[1]);
		}
		return paramType;
	}

	@Override
	public ArrayList<Listing> pass1(Command c) {
		// FIXME parameters don't work right
		ArrayList<Listing> list = new ArrayList<Listing>();
		getCompiler().getPreprocessor().enterModule(getName() + "-" + System.nanoTime());
		for (int i = 0; i < c.getParams().length; i++) {
			String param = DString.trim(c.getParams()[i]);
			String[] formatParts = DString.trim(DString.splitTopLevel(getParamFormats()[i], ':'));
			char fmtType = formatParts[0].charAt(0);
			switch (fmtType) {
				case 'R':
					param = "\"" + param + "\"";
				case 'V':
				case 'S':
				case 'N':
					getCompiler().getPreprocessor().define(formatParts[1], param);
					break;
				default:
					break;
			}
		}
		for (String line : code)
			list.addAll(getCompiler().getPreprocessor().preprocessLine(line));
		getCompiler().getPreprocessor().leaveModule();
		return list;
	}

	@Override
	public void pass2(Listing l, Command c) {
		// nothing, macros never have pass2's
	}
}
